# 作者：一只牛吗
# 2025 年03月 12日 05时 27分 57秒
# 1278599690@qq.com
import re
coding = 'utf-8'


# 本质是模式匹配
def match_test():
    result = re.match('zhang', 'zhang_zhen.yang')  # match方法默认从头开始匹配，如果匹配成功，返回一个Match对象，否则返回None
    print(result)
    print(result.group())  # 输出匹配到的字符串


def single_match_test():
    '''
    . 匹配任意1个字符除了\n
    [] 匹配字符集
    \d 匹配数字
    \w 匹配字母、数字、下划线、汉字
    \s 匹配空白字符
    \D 匹配非数字
    \W 匹配非字母、数字、下划线
    \S 匹配非空白字符
    :return:
    '''
    ret = re.match('.', ":M")
    print(ret.group())  # 输出匹配到的字符串

    ret = re.match('[a-z]', "a")
    print(ret.group())  # 输出匹配到的字符串

    ret = re.match('t.o', "too")
    print(ret.group())  # 输出匹配到的字符串

    ret = re.match('\d', "12345")
    print(ret.group())  # 输出匹配到的字符串


def multi_match_test():
    '''
    * 匹配0个或多个字符
    + 匹配1个或多个字符
    {n} 匹配前一个字符出现n次
    {n,} 匹配前一个字符至少出现n次
    {m,n} 匹配前一个字符出现m到n次
    ? 匹配0个或1个字符
    :return:
    '''
    ret = re.match('z*', "zhen")
    print(ret.group())  # 输出匹配到的字符串

    ret = re.match('z+', "zhen")
    print(ret.group())  # 输出匹配到的字符串
    # ret = re.match('z{3}', "zhen")
    # print(ret.group())  # 输出匹配到的字符串
    names = ['name1', '_name', '2_name', '__name__']
    # 验证变量名是否合法, 变量名只能以字母或下划线开头，后面可以是字母、数字、下划线
    for name in names:
        # ret = re.match('^[_a-zA-Z][_a-zA-Z0-9]*$', name)
        ret = re.match('^[a-zA-Z_]\w*', name)
        if ret:
            print(ret.group(), 'is valid')
        else:
            print(ret.group(), 'is invalid')

def start_end_test():
    '''
    ^ 匹配字符串开始位置
    注意，在[]中，^表示匹配不在[]中的字符，如[^a-z]表示匹配非小写字母
    $ 匹配字符串结束位置 意味着必须以$前的字符结尾
    :return:
    '''
    email_list = ['xiaowang@163.comheihei', '123@qq.com', 'abc@163.com', '.com.xiaowang@123.com']
    for email in email_list:
        ret = re.match(r'\w{2,20}@163\.com$', email) # 需要匹配.的时候需要转义，\转义字符
        if ret:
            print(ret.group(), 'is valid')
        else:
            try:
                print(ret.group(), 'is invalid')
            except Exception as e:
                print('⌈' + '——'*20 + '⌉')
                print(e)
                print(f'{email} is invalid')
                print('⌊'+'——' * 20+'⌋')


def matching_group_test():
    '''
    | 匹配多个模式
    () 匹配分组，并捕获分组内容
    (?P<name>pattern) 匹配pattern并捕获为name
    (?=pattern) 正向肯定界定符，匹配pattern前面的位置
    (?!pattern) 正向否定界定符，匹配pattern前面的位置
    (?<=pattern) 反向肯定界定符，匹配pattern后面的位置
    (?<!pattern) 反向否定界定符，匹配pattern后面的位置
    \num 引用分组num的内容
    :return:
    '''
    email_list = ['xiaowang@163.comheihei', '1-23@qq.com', 'abc@163.com', '.com.xiaowang@123.com']
    for email in email_list:
        ret = re.match(r'[\w\.]{2,20}@(163|qq|123)\.com', email)
        try:
            print(ret.group())
        except Exception as e:
            print('⌈' + '——'*20 + '⌉')
            print(e)
            print(f'{email} is invalid')
            print('⌊'+'——' * 20+'⌋')
    # 匹配手机号码
    phone_list = ['010-12345678', '261-73095478', '139-1234569', '139-12382046', '236-17821978', '275-34902367']
    for phone in phone_list:
        ret = re.match(r'([^-]+)-(\d+)', phone)
        if ret:
            print(ret.group())
            print(ret.group(1))
            print(ret.group(2))

def advanced_matching_group_test():
    '''
    search() 匹配字符串，返回第一个匹配的结果，和match的区别是，match从开头开始匹配，如果开头不匹配，则返回None，而search从任意位置开始匹配
    findall() 匹配字符串，返回所有匹配的结果
    sub() 替换字符串，返回替换后的字符串
    split() 分割字符串，返回分割后的列表
    :return:
    '''
    strings = '阅读次数为9999，点赞次数为666'
    print('⌈'+ '——'*20 + '⌉')
    ret = re.search(r'\d+', strings)
    print(ret.group())  # 输出匹配到的字符串
    print('⌊'+'——' * 20+'⌋')
    print('⌈'+ '——'*20 + '⌉')
    ret = re.findall(r'\d+', strings)
    print(ret)  # 输出所有匹配到的字符串
    print('⌊'+'——' * 20+'⌋')
    print('⌈'+ '——'*20 + '⌉')
    ret = re.sub(r'\d+', lambda x: str(int(x.group())+100), 'python = 997')
    print(ret)  # 输出替换后的字符串
    print('⌊'+'——' * 20+'⌋')
    ret = re.split(r'\d+', strings)
    print(ret)  # 输出分割后的列表
    ret = re.sub(r'\d+', lambda x: str(int(x.group())+100), 'python = 997 222 333 657', count=2) # count参数指定替换次数
    print(ret)  # 输出替换后的字符串，只替换了前两个数字
    ret = re.findall(r'\d+', 'python = 997 222 333 657')
    print(ret)  # 输出所有匹配到的字符串


def find_second_test(pattern, text):
    '''
    finditer() 匹配字符串，返回所有匹配的结果，返回一个迭代器，可以遍历所有匹配的结果
    :return:
    '''
    matches = re.finditer(pattern, text)
    try:
        next(matches)
        next(matches)
        second_match = next(matches)
        return second_match.group()
    except StopIteration:
        return None


def number_generator(start=0):
    '''
    生成器就是一种特殊的迭代器，它不存储所有的值，而是生成值，需要的时候才生成，节省内存
    :param start:
    :return:
    '''
    while start <= 5:
        yield start # 可以理解为程序进行到此暂停，然后返回yield的值，下次调用next(gen)时，程序从上次暂停的地方继续执行
        start += 1
    raise StopIteration


def use_compile_test():
    '''
    compile() 编译正则表达式，可以提高匹配效率
    :return:
    '''
    pattern = re.compile(r'\d+')
    text = 'abc123def456ghi789'
    ret = pattern.findall(text)
    print(ret)

def greedy_matching_test():
    '''
    贪婪匹配：正则表达式默认是贪婪匹配，即尽可能多的匹配字符，直到遇到不匹配的字符为止。
    非贪婪匹配：在正则表达式中，使用问号?表示非贪婪匹配，即尽可能少的匹配字符，直到遇到匹配的字符为止。
    :return:
    '''
    strings = ' This is a number 234-235-22-423'
    pattern = r'.+?(\d+-\d+-\d+-\d+)'
    ret = re.match(pattern, strings)
    print(ret.group(1))  # 输出匹配到的字符串


def use_option_test():
    '''
    re.A 不让\w匹配汉字（其实就是只匹配ASCII字符）
    re.I 使匹配对大小写不敏感
    re.M 多行模式，使^和$匹配每一行的开始和结束位置
    re.S 使.匹配包括换行符在内的所有字符（.默认只匹配换行符）
    re.U 使\w、\W、\b、\B、\d、\D、\s、\S匹配Unicode字符
    以下三种比较常用
    :return:
    '''
    print(re.match(r'\w*', 'abc函', flags=re.A).group())
    print(re.match(r'a*', 'aA', flags=re.I).group())
    print(re.match(r'.*', 'abc\ndef', flags=re.S).group())

if __name__ == '__main__':
    # match_test()
    # single_match_test()
    # multi_match_test()
    # start_end_test()
    matching_group_test()
    # advanced_matching_group_test()
    # text = 'abc123def456ghi789'
    # pattern = r'\d+'
    # print(find_second_test(pattern, text))
    # gen = number_generator()
    # for i in gen:
    #     print(i)
    # print(next(gen))
    # print(next(gen))
    # print(next(gen))
    # # 如果需要从其他数字开始，可以输入起始值
    # gen2 = number_generator(100)
    # print(next(gen2))
    # print(next(gen2))
    # use_compile_test()
    # greedy_matching_test()
    # use_option_test()